package org.louie.hypercube;

import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL11;

import static org.lwjgl.glfw.GLFW.GLFW_PRESS;

public class Cube4D {


    private float angleXW = 0.02f;
    private float angleYW = 0.02f;
    private float angleZW = 0.02f;
    private float angleXY = 0.02f;
    private float angleYZ = 0.02f;
    private float angleXZ = 0.02f;
    float[][] hypercubeVertices = {
            {-1, -1, -1, -1}, {1, -1, -1, -1}, {1, 1, -1, -1}, {-1, 1, -1, -1},
            {-1, -1, 1, -1}, {1, -1, 1, -1}, {1, 1, 1, -1}, {-1, 1, 1, -1},
            {-1, -1, -1, 1}, {1, -1, -1, 1}, {1, 1, -1, 1}, {-1, 1, -1, 1},
            {-1, -1, 1, 1}, {1, -1, 1, 1}, {1, 1, 1, 1}, {-1, 1, 1, 1}
    };
    int[][] hypercubeEdges = {
            {0, 1}, {1, 2}, {2, 3}, {3, 0},  // 立方体 1
            {4, 5}, {5, 6}, {6, 7}, {7, 4},  // 立方体 2
            {0, 4}, {1, 5}, {2, 6}, {3, 7},  // 连接前后 3D 立方体
            {8, 9}, {9, 10}, {10, 11}, {11, 8},  // 立方体 3
            {12, 13}, {13, 14}, {14, 15}, {15, 12},  // 立方体 4
            {8, 12}, {9, 13}, {10, 14}, {11, 15},  // 连接前后 3D 立方体
            {0, 8}, {1, 9}, {2, 10}, {3, 11},  // 连接 4D 维度
            {4, 12}, {5, 13}, {6, 14}, {7, 15}   // 连接 4D 维度
    };
    private float[][] colors = {
            {1.0f, 0.0f, 0.0f}, // 红色
            {0.0f, 1.0f, 0.0f}, // 绿色
            {0.0f, 0.0f, 1.0f}, // 蓝色
            {1.0f, 1.0f, 0.0f}, // 黄色
            {1.0f, 0.0f, 1.0f}, // 紫色
            {0.0f, 1.0f, 1.0f}, // 青色
            {1.0f, 0.5f, 0.0f}, // 橙色
            {0.5f, 0.5f, 0.5f}  // 灰色
    };
    // 8 个 3D 立方体，每个由 8 个顶点组成
    private int[][] hypercubeCells = {
            {0, 1, 3, 2, 4, 5, 7, 6},  // 第 1 个 3D 立方体
            {0, 1, 5, 4, 8, 9, 13, 12}, // 第 2 个 3D 立方体
            {1, 3, 7, 5, 9, 11, 15, 13}, // 第 3 个 3D 立方体
            {3, 2, 6, 7, 11, 10, 14, 15}, // 第 4 个 3D 立方体
            {2, 0, 4, 6, 10, 8, 12, 14}, // 第 5 个 3D 立方体
            {8, 9, 11, 10, 12, 13, 15, 14}, // 第 6 个 3D 立方体
            {4, 5, 7, 6, 12, 13, 15, 14}, // 第 7 个 3D 立方体
            {8, 9, 11, 10, 0, 1, 3, 2}  // 第 8 个 3D 立方体
    };
    private int[][] cellFaces = {
            {0, 1, 3, 2}, // 前面
            {4, 5, 7, 6}, // 后面
            {0, 1, 5, 4}, // 左面
            {2, 3, 7, 6}, // 右面
            {0, 2, 6, 4}, // 底面
            {1, 3, 7, 5}  // 顶面
    };

    /**
     * 将4D坐标投影到3D空间。
     * 该方法使用一个控制投影强度的参数d，将4D坐标 (x, y, z, w) 投影到3D空间 (x', y', z')。
     *
     * @param x 4D坐标的x分量
     * @param y 4D坐标的y分量
     * @param z 4D坐标的z分量
     * @param w 4D坐标的w分量
     * @return 返回投影后的3D坐标数组 [x', y', z']
     */
    private float[] project4DTo3D(float x, float y, float z, float w) {
        float d = 3.0f; // 控制投影强度
        float scale = 1.0f / (d - w);
        // 计算投影后的3D坐标
        return new float[]{x * scale, y * scale, z * scale};
    }


    private void drawHypercube() {
        GL11.glBegin(GL11.GL_LINES);
        GL11.glColor3f(0.0f, 1.0f, 1.0f); // 颜色（青色）

        for (int[] edge : hypercubeEdges) {
            // 获取 4D 顶点
            float[] v1 = hypercubeVertices[edge[0]];
            float[] v2 = hypercubeVertices[edge[1]];

            // 投影到 3D
            float[] p1 = project4DTo3D(v1[0], v1[1], v1[2], v1[3]);
            float[] p2 = project4DTo3D(v2[0], v2[1], v2[2], v2[3]);

            // 画线
            GL11.glVertex3f(p1[0], p1[1], p1[2]);
            GL11.glVertex3f(p2[0], p2[1], p2[2]);
        }

        GL11.glEnd();
    }



    private float[] rotate4D(float x, float y, float z, float w) {
        float cosXW = (float) Math.cos(angleXW), sinXW = (float) Math.sin(angleXW);
        float cosYW = (float) Math.cos(angleYW), sinYW = (float) Math.sin(angleYW);
        float cosZW = (float) Math.cos(angleZW), sinZW = (float) Math.sin(angleZW);
        float cosXY = (float) Math.cos(angleXY), sinXY = (float) Math.sin(angleXY);
        float cosYZ = (float) Math.cos(angleYZ), sinYZ = (float) Math.sin(angleYZ);
        float cosXZ = (float) Math.cos(angleXZ), sinXZ = (float) Math.sin(angleXZ);

        // X-W 旋转
        float newX = cosXW * x - sinXW * w;
        float newW = sinXW * x + cosXW * w;
        x = newX;
        w = newW;

        // Y-W 旋转
        float newY = cosYW * y - sinYW * w;
        newW = sinYW * y + cosYW * w;
        y = newY;
        w = newW;

        // Z-W 旋转
        float newZ = cosZW * z - sinZW * w;
        newW = sinZW * z + cosZW * w;
        z = newZ;
        w = newW;

        // X-Y 旋转
        newX = cosXY * x - sinXY * y;
        newY = sinXY * x + cosXY * y;
        x = newX;
        y = newY;

        // Y-Z 旋转
        newY = cosYZ * y - sinYZ * z;
        newZ = sinYZ * y + cosYZ * z;
        y = newY;
        z = newZ;

        // X-Z 旋转
        newX = cosXZ * x - sinXZ * z;
        newZ = sinXZ * x + cosXZ * z;

        return new float[]{newX, newY, newZ, newW};
    }


    public void drawRotatingHypercube3() {
        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

        // 开启深度测试，防止前面覆盖后面的错误
        GL11.glEnable(GL11.GL_DEPTH_TEST);
        GL11.glDepthMask(false); // 禁用深度写入

        // 缓存旋转后的顶点和投影后的坐标
        float[][] projectedVertices = new float[hypercubeVertices.length][3];
        for (int i = 0; i < hypercubeVertices.length; i++) {
            float[] v = rotate4D(hypercubeVertices[i][0], hypercubeVertices[i][1], hypercubeVertices[i][2], hypercubeVertices[i][3]);
            projectedVertices[i] = project4DTo3D(v[0], v[1], v[2], v[3]);
        }

        // 先画透明面
        GL11.glBegin(GL11.GL_QUADS);
        for (int i = 0; i < hypercubeCells.length; i++) {
            int[] cell = hypercubeCells[i];
            float[] color = colors[i];

            // 增加颜色的饱和度，防止透明时颜色变浅
            float red = Math.min(color[0] * 1.5f, 1.0f);
            float green = Math.min(color[1] * 1.5f, 1.0f);
            float blue = Math.min(color[2] * 1.5f, 1.0f);

            // 设置颜色（加透明度 alpha = 0.5f）
            GL11.glColor4f(red, green, blue, 0.5f);

            // 绘制每个面
            for (int[] face : cellFaces) {
                for (int k = 0; k < 4; k++) {
                    int vertexIndex = cell[face[k]];
                    float[] p = projectedVertices[vertexIndex];
                    GL11.glVertex3f(p[0], p[1], p[2]);
                }
            }
        }
        GL11.glEnd();

        // 关闭透明混合（避免影响边框）
        GL11.glDisable(GL11.GL_BLEND);

        // 恢复深度写入
        GL11.glDepthMask(true);

        // 画黑色边框（线框模式）
        GL11.glColor3f(0.0f, 0.0f, 0.0f);
        GL11.glLineWidth(2.0f); // 线条加粗
        GL11.glBegin(GL11.GL_LINES);
        for (int[] edge : hypercubeEdges) {
            float[] v1 = projectedVertices[edge[0]];
            float[] v2 = projectedVertices[edge[1]];
            GL11.glVertex3f(v1[0], v1[1], v1[2]);
            GL11.glVertex3f(v2[0], v2[1], v2[2]);
        }
        GL11.glEnd();
    }

    private void drawRotatingHypercube() {
        GL11.glBegin(GL11.GL_LINES);

        for (int i = 0; i < hypercubeEdges.length; i++) {
            int[] edge = hypercubeEdges[i];

            // 获取 4D 顶点
            float[] v1 = rotate4D(hypercubeVertices[edge[0]][0], hypercubeVertices[edge[0]][1],
                    hypercubeVertices[edge[0]][2], hypercubeVertices[edge[0]][3]);
            float[] v2 = rotate4D(hypercubeVertices[edge[1]][0], hypercubeVertices[edge[1]][1],
                    hypercubeVertices[edge[1]][2], hypercubeVertices[edge[1]][3]);

            // 投影到 3D
            float[] p1 = project4DTo3D(v1[0], v1[1], v1[2], v1[3]);
            float[] p2 = project4DTo3D(v2[0], v2[1], v2[2], v2[3]);

            // **确定当前边属于哪个 3D 立方体**
            int cubeIndex = edge[0] / 4;  // 8 个 3D 立方体（每个 4 个点）
            float[] color = colors[cubeIndex];

            // **设置颜色**
            GL11.glColor3f(color[0], color[1], color[2]);

            // 画线
            GL11.glVertex3f(p1[0], p1[1], p1[2]);
            GL11.glVertex3f(p2[0], p2[1], p2[2]);
        }

        GL11.glEnd();
    }


    public void processInput(long window) {
        float rotationSpeed = (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) ? 0.03f : 0.01f;

        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_W) == GLFW_PRESS) angleXW += rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_S) == GLFW_PRESS) angleXW -= rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_E) == GLFW_PRESS) angleYW += rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_D) == GLFW_PRESS) angleYW -= rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_R) == GLFW_PRESS) angleZW += rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_F) == GLFW_PRESS) angleZW -= rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_A) == GLFW_PRESS) angleXY += rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_Q) == GLFW_PRESS) angleXY -= rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_T) == GLFW_PRESS) angleYZ += rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_G) == GLFW_PRESS) angleYZ -= rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_Z) == GLFW_PRESS) angleXZ += rotationSpeed;
        if (GLFW.glfwGetKey(window, GLFW.GLFW_KEY_X) == GLFW_PRESS) angleXZ -= rotationSpeed;
    }


}
